/*
 * Copyright (C) 2010- Peer internet solutions
 * 
 * This file is part of mixare.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>
 */
package com.seguriapp.data;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import com.seguriapp.activities.MixViewActivity;
import com.seguriapp.data.DataSource.DATAFORMAT;
import com.seguriapp.entities.Marker;
import com.seguriapp.entities.SocialMarker;

public class Json extends DataHandler {

	public static final int MAX_JSON_OBJECTS = 1000;

	public List<Marker> load(JSONObject root, DATAFORMAT dataformat) {
		JSONObject jo = null;
		JSONArray dataArray = null;
		List<Marker> markers = new ArrayList<Marker>();

		try {

			if (root.has("results")) { // Twitter & own schema
				dataArray = root.getJSONArray("results");
			} else if (root.has("criminalItems")) { // Crime
				dataArray = root.getJSONArray("criminalItems");
			} else if (root.has("entitiesList")) { // Entity
				dataArray = root.getJSONArray("entitiesList");
			} else if (root.has("data")
					&& root.getJSONObject("data").has("items")) { // Google Buzz
				dataArray = root.getJSONObject("data").getJSONArray("items");
			}
			if (dataArray != null) {

				Log.i(MixViewActivity.TAG, "processing " + dataformat
						+ " JSON Data Array");
				int top = Math.min(MAX_JSON_OBJECTS, dataArray.length());

				for (int i = 0; i < top; i++) {

					jo = dataArray.getJSONObject(i);
					Marker ma = null;
					switch (dataformat) {
					case SEGURIAPP_ENTITY:
						ma = processEntityJson(jo);
						break;
					case SEGURIAPP_CRIME:
						ma = processCrimeJson(jo);
						break;
					case TWITTER:
						ma = processTwitterJSONObject(jo);
						break;
					// case SEGURIAPP22: ma = processWikipediaJSONObject(jo);
					// break;
					// case DENUNCIAME_CSI: ma = processCSIjSONObject(jo);
					// break;
					default:
						ma = processEntityJson(jo);
						break;
					}
					if (ma != null)
						markers.add(ma);
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return markers;
	}

	// public List<CrimeEntity> loadCSI(JSONObject root, DATAFORMAT dataformat)
	// {
	// JSONObject jo = null;
	// JSONArray dataArray = null;
	// List<CrimeEntity> markers=new ArrayList<CrimeEntity>();
	// if (root.has("geonames")){
	// try {
	// dataArray = root.getJSONArray("geonames");
	// if (dataArray != null) {
	//
	// Log.i(MixViewActivity.TAG, "processing "+dataformat+" JSON Data Array");
	// int top = Math.min(MAX_JSON_OBJECTS, dataArray.length());
	//
	// for (int i = 0; i < top; i++) {
	//
	// jo = dataArray.getJSONObject(i);
	// CrimeEntity ma = null;
	// switch(dataformat) {
	// case DENUNCIAME_CSI: ma = processCSIjSONObject(jo); break;
	// }
	// if(ma!=null){
	// markers.add(ma);
	// }
	// }
	// }
	// } catch (JSONException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// }
	//
	// return markers;
	// }

	public Marker processBuzzJSONObject(JSONObject jo)
			throws NumberFormatException, JSONException {
		Marker ma = null;
		if (jo.has("title") && jo.has("geocode") && jo.has("links")) {
			Log.v(MixViewActivity.TAG, "processing Google Buzz JSON object");

			ma = new SocialMarker(jo.getString("title"), Double.valueOf(jo
					.getString("geocode").split(" ")[0]), Double.valueOf(jo
					.getString("geocode").split(" ")[1]), 0, jo
					.getJSONObject("links").getJSONArray("alternate")
					.getJSONObject(0).getString("href"),
					DataSource.DATASOURCE.BUZZ);
		}
		return ma;
	}

	public Marker processTwitterJSONObject(JSONObject jo)
			throws NumberFormatException, JSONException {
		Marker ma = null;
		if (jo.has("geo")) {
			Double lat = null, lon = null;

			if (!jo.isNull("geo")) {
				JSONObject geo = jo.getJSONObject("geo");
				JSONArray coordinates = geo.getJSONArray("coordinates");
				lat = Double.parseDouble(coordinates.getString(0));
				lon = Double.parseDouble(coordinates.getString(1));
			} else if (jo.has("location")) {

				// Regex pattern to match location information
				// from the location setting, like:
				// iPhone: 12.34,56.78
				// ÃœT: 12.34,56.78
				// 12.34,56.78

				Pattern pattern = Pattern
						.compile("\\D*([0-9.]+),\\s?([0-9.]+)");
				Matcher matcher = pattern.matcher(jo.getString("location"));

				if (matcher.find()) {
					lat = Double.parseDouble(matcher.group(1));
					lon = Double.parseDouble(matcher.group(2));
				}
			}
			if (lat != null) {
				Log.v(MixViewActivity.TAG, "processing Twitter JSON object");
				String user = jo.getString("from_user");
				String url = "http://twitter.com/" + user;

				ma = new SocialMarker(user + ": " + jo.getString("text"), lat,
						lon, 0, url, DataSource.DATASOURCE.TWITTER);
			}
		}
		return ma;
	}

	public Marker processEntityJson(JSONObject jo) throws JSONException {

		Marker ma = null;
		String link = null;

		if (jo.has("has_detail_page") && jo.getInt("has_detail_page") != 0
				&& jo.has("webpage"))
			link = jo.getString("webpage");

		try {
			ma = new SocialMarker(unescapeHTML(
					URLDecoder.decode(jo.getString("title"), "ISO-8859-1"), 0),
					jo.getDouble("latitude"), jo.getDouble("longitude"),
					jo.getDouble("altitude"), link,
					DataSource.DATASOURCE.SEGURIAPP_ENTITY);
		} catch (UnsupportedEncodingException e) {
			Log.e("UnsupportedEncodingException", e.getMessage());
		}

		return ma;
	}

	public Marker processCrimeJson(JSONObject jo) throws JSONException {
		Marker ma = null;
		final String title = jo.getJSONArray("crimeDescriptionList")
				.getJSONObject(0).getJSONObject("category").getString("name");

		try {
			ma = new SocialMarker(unescapeHTML(
					URLDecoder.decode(title, "ISO-8859-1"), 0),
					jo.getDouble("latitude"), jo.getDouble("longitude"), 0,
					"yeah", DataSource.DATASOURCE.SEGURIAPP_CRIME);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return ma;
	}

	// public Marker processWikipediaJSONObject(JSONObject jo) throws
	// JSONException {
	//
	// Marker ma = null;
	// if (jo.has("latitude") && jo.has("longitude")) {
	//
	// Log.v(MixViewActivity.TAG, "processing Wikipedia JSON object");
	// String crimen;
	// if (jo.has("title")) {
	// crimen = jo.getString("title");
	// } else {
	// crimen = "Crimen";
	// }
	//
	// String url;
	// if (jo.has("url")) {
	// url = jo.getString("url");
	// } else {
	// url = "www.pucp.edu.pe";
	// }
	// ma = new SocialMarker(
	// // unescapeHTML(jo.getString("title"), 0),
	// // URLDecoder.decode(jo.getString("title"),"utf-8"),
	// crimen, jo.getDouble("latitude"), jo.getDouble("longitude"),
	// // jo.getDouble("elevation"),
	// 0, url, DataSource.DATASOURCE.SEGURIAPP22);
	//
	// }
	// return ma;
	// }

	private static HashMap<String, String> htmlEntities;
	static {
		htmlEntities = new HashMap<String, String>();
		htmlEntities.put("&lt;", "<");
		htmlEntities.put("&gt;", ">");
		htmlEntities.put("&amp;", "&");
		htmlEntities.put("&quot;", "\"");
		htmlEntities.put("&agrave;", "Ã ");
		htmlEntities.put("&Agrave;", "Ã€");
		htmlEntities.put("&acirc;", "Ã¢");
		htmlEntities.put("&auml;", "Ã¤");
		htmlEntities.put("&Auml;", "Ã„");
		htmlEntities.put("&Acirc;", "Ã‚");
		htmlEntities.put("&aring;", "Ã¥");
		htmlEntities.put("&Aring;", "Ã…");
		htmlEntities.put("&aelig;", "Ã¦");
		htmlEntities.put("&AElig;", "Ã†");
		htmlEntities.put("&ccedil;", "Ã§");
		htmlEntities.put("&Ccedil;", "Ã‡");
		htmlEntities.put("&eacute;", "Ã©");
		htmlEntities.put("&Eacute;", "Ã‰");
		htmlEntities.put("&egrave;", "Ã¨");
		htmlEntities.put("&Egrave;", "Ãˆ");
		htmlEntities.put("&ecirc;", "Ãª");
		htmlEntities.put("&Ecirc;", "ÃŠ");
		htmlEntities.put("&euml;", "Ã«");
		htmlEntities.put("&Euml;", "Ã‹");
		htmlEntities.put("&iuml;", "Ã¯");
		htmlEntities.put("&Iuml;", "Ã�");
		htmlEntities.put("&ocirc;", "Ã´");
		htmlEntities.put("&Ocirc;", "Ã�?");
		htmlEntities.put("&ouml;", "Ã¶");
		htmlEntities.put("&Ouml;", "Ã–");
		htmlEntities.put("&oslash;", "Ã¸");
		htmlEntities.put("&Oslash;", "Ã˜");
		htmlEntities.put("&szlig;", "ÃŸ");
		htmlEntities.put("&ugrave;", "Ã¹");
		htmlEntities.put("&Ugrave;", "Ã™");
		htmlEntities.put("&ucirc;", "Ã»");
		htmlEntities.put("&Ucirc;", "Ã›");
		htmlEntities.put("&uuml;", "Ã¼");
		htmlEntities.put("&Uuml;", "Ãœ");
		htmlEntities.put("&nbsp;", " ");
		htmlEntities.put("&copy;", "\u00a9");
		htmlEntities.put("&reg;", "\u00ae");
		htmlEntities.put("&euro;", "\u20a0");
		htmlEntities.put("%3F", "'í");

	}

	public String unescapeHTML(String source, int start) {
		int i, j;

		i = source.indexOf("&", start);
		if (i == -1) {
			i = source.indexOf("%", start);
		}
		if (i > -1) {
			j = source.indexOf(";", i);
			if (j == -1) {
				j = source.indexOf("F", i);
			}
			if (j > i) {
				String entityToLookFor = source.substring(i, j + 1);
				String value = (String) htmlEntities.get(entityToLookFor);
				if (value != null) {
					source = new StringBuffer().append(source.substring(0, i))
							.append(value).append(source.substring(j + 1))
							.toString();
					return unescapeHTML(source, i + 1); // recursive call
				}
			}
		}
		return source;
	}
}